from queue import Queue
from threading import Thread
import time

_sentinel = object()


def producer(q: Queue, n=30):
    i = 0
    while True:
        i += 1
        if i <= n:
            q.put(i)
            print(f'>>> {i}')
        else:
            q.put(_sentinel)
            print(f'>>> END')
            break
        time.sleep(0.1)


def consumer(q: Queue, name: str):
    while True:
        n = q.get()
        print(f'<<<<<< {n} by {name}')
        if n is _sentinel:
            print(f'<<<<<< END by {name}')
            q.put(n)
            break
        # time.sleep(0.2)  # consumer need not sleep


the_queue = Queue()
t1 = Thread(target=producer, args=(the_queue, 10, ))
t1.start()
t2 = Thread(target=consumer, args=(the_queue, 'A'))
t3 = Thread(target=consumer, args=(the_queue, 'B'))
t2.start()
t3.start()

t1.join()
t2.join()
t3.join()
print('In main ...')
print('All over')
